package com.dzm.xgb.core.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.dzm.common.exception.Assert;
import com.dzm.common.result.ResponseEnum;
import com.dzm.xgb.core.enums.LendStatusEnum;
import com.dzm.xgb.core.enums.TransTypeEnum;
import com.dzm.xgb.core.hfb.FormHelper;
import com.dzm.xgb.core.hfb.HfbConst;
import com.dzm.xgb.core.hfb.RequestHelper;
import com.dzm.xgb.core.pojo.entity.*;
import com.dzm.xgb.core.mapper.LendReturnMapper;
import com.dzm.xgb.core.service.*;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.dzm.xgb.core.utils.LendNoUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * <p>
 * 还款记录表 服务实现类
 * </p>
 *
 * @author Dzm
 * @since 2024-08-27
 */
@Service
public class LendReturnServiceImpl extends ServiceImpl<LendReturnMapper, LendReturn> implements LendReturnService {

    @Autowired
    private UserAccountService userAccountService;

    @Autowired
    private TransFlowService transFlowService;

    @Autowired
    private UserInfoService userInfoService;

    @Autowired
    private LendItemReturnService lendItemReturnService;

    @Autowired
    private LendService lendService;

    @Autowired
    private LendItemService lendItemService;


    @Override
    public List<LendReturn> getListByLendId(Long id) {
        List<LendReturn> list = this.list(new LambdaQueryWrapper<LendReturn>()
                .eq(LendReturn::getLendId, id));
        return list;
    }

    @Override
    public String commitReturn(Long lendReturnId, Long userId) {
        UserInfo userInfo = userInfoService.getById(userId);
        LendReturn lendReturn = this.getById(lendReturnId);
        Lend lend = lendService.getById(lendReturn.getLendId());
        //还款人身份校验
        Assert.isTrue(lendReturn.getUserId().equals(userId), ResponseEnum.BORROWER_INFO_ERROR);
        //还款人资金校验
        BigDecimal account = userAccountService.getAccount(userId); //当前还款人资金
        Assert.isTrue(account.compareTo(lendReturn.getTotal()) >= 0, ResponseEnum.NOT_SUFFICIENT_FUNDS_ERROR);

        //查出与该还款计划所关联得回款计划列表
        List<Map<String, Object>> data = getListByLendReturnId(lendReturn.getId());

        Map<String, Object> param = new HashMap<>();
        param.put("agentId", HfbConst.AGENT_ID);
        param.put("agentGoodsName", lend.getTitle());   //标的名称
        param.put("agentBatchNo", lendReturn.getReturnNo());//批次号
        param.put("fromBindCode", userInfo.getBindCode());
        param.put("totalAmt", lendReturn.getTotal());   //要还得本息
        param.put("note", "用户" + userId + "还款");
        param.put("data", JSONObject.toJSONString(data));
        param.put("voteFeeAmt", BigDecimal.ZERO);
        param.put("notifyUrl", HfbConst.BORROW_RETURN_NOTIFY_URL);
        param.put("returnUrl", HfbConst.BORROW_RETURN_URL);
        param.put("timestamp", RequestHelper.getTimestamp());
        param.put("sign", RequestHelper.getSign(param));

        String formStr = FormHelper.buildForm(HfbConst.BORROW_RETURN_URL, param);
        return formStr;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public String notifyBorrowerReturn(Map<String, Object> map) {
        String agentBatchNo = (String) map.get("agentBatchNo");

        //幂等性判断
        TransFlow transFlow = transFlowService.getOne(new LambdaQueryWrapper<TransFlow>()
                .eq(TransFlow::getTransNo, agentBatchNo));
        if(transFlow != null) {
            return "success";
        }
        //获取当前还款计划
        LendReturn lendReturn = this.getOne(new LambdaQueryWrapper<LendReturn>()
                .eq(LendReturn::getReturnNo, agentBatchNo));
        lendReturn.setStatus(1);
        lendReturn.setFee(new BigDecimal((String) map.get("voteFeeAmt")));
        lendReturn.setRealReturnTime(LocalDateTime.now());
        this.updateById(lendReturn);

        //如果是最后一次还款则设置标的状态为已还清
        if(lendReturn.getLast()) {
            Lend lend = lendService.getById(lendReturn.getLendId());
            lend.setStatus(LendStatusEnum.PAY_OK.getStatus());
            lendService.updateById(lend);
        }

        //借款账号资金转出
        UserInfo borrowUser = userInfoService.getById(lendReturn.getUserId());
        BigDecimal totalAmt = new BigDecimal((String) map.get("totalAmt"));
        userAccountService.updateUserAccount(borrowUser.getBindCode(), totalAmt.negate(), BigDecimal.ZERO);
        Lend lend = lendService.getById(lendReturn.getLendId());

        //还款交易流水
        transFlow = new TransFlow();
        transFlow.setMemo(String.format("借款人还款扣减，项目编号：%s，项目名称：%s", lend.getLendNo(), lend.getTitle()));
        transFlow.setTransAmount(totalAmt);
        transFlow.setTransNo(agentBatchNo);
        transFlow.setTransType(TransTypeEnum.RETURN_DOWN.getTransType());
        transFlow.setTransTypeName(TransTypeEnum.getTransTypeName(transFlow.getTransType()));
        transFlow.setUserId(borrowUser.getId());
        transFlow.setUserName(borrowUser.getName());
        transFlowService.save(transFlow);

        //修改回款明细
        List<LendItemReturn> lendItemReturnList = lendItemReturnService.list(new LambdaQueryWrapper<LendItemReturn>()
                .eq(LendItemReturn::getLendReturnId, lendReturn.getId()));
        for (LendItemReturn lendItemReturn : lendItemReturnList) {
            lendItemReturn.setStatus(1);
            lendItemReturn.setRealReturnTime(LocalDateTime.now());
            lendItemReturnService.updateById(lendItemReturn);

            //更新标的项信息
            Long lendItemId = lendItemReturn.getLendItemId();
            LendItem lendItem = lendItemService.getById(lendItemId);
            lendItem.setRealAmount(lendItemReturn.getInterest());
            lendItemService.updateById(lendItem);

            //投资账号资金修改
            UserInfo investUser = userInfoService.getById(lendItem.getInvestUserId());
            userAccountService.updateUserAccount(investUser.getBindCode(), lendItemReturn.getTotal(), BigDecimal.ZERO);

            //添加回款交易流水
            transFlow = new TransFlow();
            transFlow.setMemo(String.format("还款到账，项目编号：%s，项目名称：%s", lend.getLendNo(), lend.getTitle()));
            transFlow.setTransAmount(lendItemReturn.getTotal());
            transFlow.setTransNo(LendNoUtils.getReturnItemNo());
            transFlow.setTransType(TransTypeEnum.INVEST_BACK.getTransType());
            transFlow.setTransTypeName(TransTypeEnum.getTransTypeName(transFlow.getTransType()));
            transFlow.setUserId(investUser.getId());
            transFlow.setUserName(investUser.getName());
            transFlowService.save(transFlow);
        }

        return "success";
    }

    private List<Map<String, Object>> getListByLendReturnId(Long id) {
        LendReturn lendReturn = this.getById(id);
        Lend lend = lendService.getById(lendReturn.getLendId());

        //封装还款计划所关联得回款计划列表
        List<LendItemReturn> lendItemReturnList = lendItemReturnService.list(new LambdaQueryWrapper<LendItemReturn>()
                .eq(LendItemReturn::getLendReturnId, lendReturn.getId()));
        List<Map<String, Object>> lendItemReturnListMap = lendItemReturnList.stream()
                .map(lendItemReturn -> {
                    //获取当前回款计划对应的投资项
                    LendItem lendItem = lendItemService.getById(lendItemReturn.getLendItemId());
                    //投资人
                    UserInfo invertUser = userInfoService.getById(lendItem.getInvestUserId());

                    Map<String, Object> map = new HashMap<>();
                    map.put("agentProjectCode", lend.getLendNo());
                    map.put("voteBillNo", lendItem.getLendItemNo());
                    map.put("toBindCode", invertUser.getBindCode());
                    map.put("transitAmt", lendItemReturn.getTotal());
                    map.put("baseAmt", lendItemReturn.getPrincipal());
                    map.put("benifitAmt", lendItemReturn.getInterest());
                    map.put("feeAmt", lendItemReturn.getFee());

                    return map;
                }).collect(Collectors.toList());


        return lendItemReturnListMap;
    }
}
